Skip to content

WEBGPU: make batchMesh._matricesTexture optional #30990

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from

Conversation

vegarringdal
Copy link
Contributor

I dont use batchMesh._matricesTexture and cant switch to webgpu without modifications
With these changes it works

Copy link

github-actions bot commented Apr 24, 2025

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 336.33
78.33
336.33
78.33
+0 B
+0 B
WebGPU 547.45
151.77
547.5
151.78
+57 B
+16 B
WebGPU Nodes 546.8
151.61
546.85
151.63
+57 B
+15 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Before After Diff
WebGL 465.78
112.28
465.78
112.28
+0 B
+0 B
WebGPU 622.3
168.35
622.36
168.37
+57 B
+18 B
WebGPU Nodes 577.17
157.62
577.23
157.63
+57 B
+12 B

);
let batchingMatrix = mat4();

if ( matricesTexture !== null ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gkjohnson Is BatchedMesh._matricesTexture supposed to be optional?

Copy link
Contributor Author

@vegarringdal vegarringdal Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more info why I need it to be optional
Im using a custom batched mesh and set it to be .isBatchedMesh = true; and just need to control _multiDrawCounts / _multiDrawStarts / _multiDrawCount mye self.

export class CustomBatchedMesh extends Mesh {
    constructor(
        geometry: BufferGeometry,
        material: MeshStandardMaterialExt,
        multiDrawCounts: Int32Array,
        multiDrawStarts: Int32Array,
        multiDrawCount: number,
        isSelected: boolean,
        isTransformed: boolean,
        opacity_override: number
    ) {
        super(geometry, material as any);

        this.material = material;

        this.isBatchedMesh = true;
      

        this._multiDrawCounts = multiDrawCounts;
        this._multiDrawStarts = multiDrawStarts;
        this._multiDrawCount = multiDrawCount;

        //just to override defaults
        this._matricesTexture = null;
        this._indirectTexture = null;
        this._colorsTexture = null;

Been working very nice to keep drawcalls down on merged mesh, and would be nice to start trying out webgpu in my application without needing to modify threejs on each release

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm not sure we should support this custom design. Instead, I wonder if we could modify BatchedMesh to accommodate your use case and then provide proper support in the renderers.

Do you mind explaining in more detail why you can't use BatchedMesh and what parts had to be changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really need to be able to use webgl multidraw. No need for different world transformations/different colors on merged mesh. So basicly dont need any of these:

_matricesTexture
_indirectTexture
_colorsTexture

Batchmesh already do same check for colorsTexture here:

if ( colorsTexture !== null ) {

and here:

if ( object._colorsTexture !== null ) {
cacheKey += object._colorsTexture.uuid + ',';
}

So Ive only added a additional check, so Batchmesh can be used without the textures without any modifications to the core. This wont really break anything from what I can tell.
Ofc, @gkjohnson would be the best guy to ask to be sure :-)

Really just want to start trying out webgpu more with minimal changes to my application. Its a lot more stable and faster now 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried creating an empty texture and using other means for indirection or batched values (e.g., a UBO)?

Note that although the texture will still be created on the GPU, only active uniforms count towards shader resource limits.

Copy link
Collaborator

@gkjohnson gkjohnson Apr 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the use case but can you please provide some numbers and explanations about what real problems it's causing. Eg "before removing the matrix texture I wasn't able to load W model" and "my batched mesh has X number of nodes so it's Y big, taking up Z MB".

I believe this is beneficial - I just know it's tempting to chase down every little thing that seems like it might be a problem (I've done it myself) and I want to have some real data for us to reason about.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dont have any real numbers to show in my app without a lot of rewrites, think it needed a additional attribute for the colors if I dont remember wrong, and GPU had hard hit when _multiDrawStarts/_multiDrawCounts/_multiDrawCount got to high on some of the models when I tried to control all items with own start/count.

Have many items on projects(best is 350K, worst is 4million+), so need to batch each mesh per coloring/transformation.
If I need new material/transformation, I create new meshes and reuse the geometry uploaded on gpu.

Small video when I do selection/coloring & transform with undo/redo.
https://drive.google.com/file/d/1tMQIWWE1A0Odz1BI2sGT7ke6mtG_ujJg/view?usp=sharing

Maybe there is better ways I could have done this I did not see when I made the app. Not the first time 😄
Just trying to make my app work with webgpu without any logic changes, so I can try it out more.
If I dont remember wrong, in webgl I just set batching to false on before compile of material to get around it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since tsl makes it easier to extend/generate shader logic, maybe core could have been a MultiDrawMesh(geometry, material, textures: map<string, texture>)
Then more advanced logic on how to use this just lived in addons ?
But again, i really dont know enough about tsl or core to know if this was a really dumb idea 😂

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coming back around to this -

Dont have any real numbers to show in my app without a lot of rewrites, think it needed a additional attribute for the colors if I dont remember wrong

I think generally I expect something concrete to demonstrate why this is helpful. Comments like "I remember it being slow" makes a problem difficult to verify and ensure a suggested change is actually causing an issue. That said there shouldn't be any app changes required to provide what I asked for:

"my batched mesh has X number of nodes so it's Y big, taking up Z MB"

The matrices texture requires 16 floats per instance which amounts to ~22.4MB when 350K instances are used or when 256MB there are 4 million instances even before the textures are forced to a power of two:

instanceCount * 16 * 4 * 1e-6

Those numbers are fairly significant if the transformations aren't being used and to me seem like a worthwhile addition especially in cases like CAD or BIM rendering where memory is already tight. We will need to modify the WebGL code path as well, though. #29084 can be referenced for the WebGL changes - but perhaps they can happen in a separate PR.

Also I'm not familiar with the TSL code path but last I heard BatchedMesh wasn't quite fully supported, yet (or at least not performant). Perhaps that's changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I checked last time for my usage I was around the same. Noticed I could load more onto gpu memory on some smaller pcs, but less on samsung s9+ pad. But did very limited testing since I hit this issue. Mostly been trying it in between to prepare a little for when its considered ready for usage. Been to busy getting stuff done before summer vacation, so Im 2 versions behind on threejs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants